
`include "defines.v"

//----------------------------------------------------------------
//Module Name : exe_stage.v
//Description of module:
//exe 
//----------------------------------------------------------------
//Designer:	Tang Pengyu
//Date: 2021/07/15	  
//----------------------------------------------------------------


module exe_stage(
  input	rst,
  input	[5:0] inst_type_i,
  input	[7:0] inst_opcode,
  input	[`REG_DATA_LEN-1:0] op1,
  input	[`REG_DATA_LEN-1:0] op2,
  input	[`REG_DATA_LEN-1:0]	extend_imm,
  input	[6:0]	funct7,
  input	[`INST_ADDR_LEN-1:0] pc,
  input	[`REG_DATA_LEN-1:0] csr_r_data,
  
  output	[5:0] inst_type_o,
  output	reg [`REG_DATA_LEN-1:0] exe_data
);

assign	inst_type_o = inst_type_i;
wire	[63:0] adder;
wire	[63:0] suber;
wire	[63:0] sller;			//<<
wire	[63:0] srler;			//逻辑右移
wire	[63:0] sraer;			//算术右移
wire	[31:0] sllwer;
wire	[31:0] srlwer;			//逻辑右移字
wire	[31:0] srawer;			//算术右移字
assign	adder = op1 + op2;
assign	suber = op1 - op2;
assign	sller = op1 << (op2[5:0]);
assign	srler = op1 >> (op2[5:0]);
assign	sraer = (({`REG_DATA_LEN{op1[`REG_DATA_LEN-1]}} << (~op2[5:0])) | (op1 >> op2[5:0]));
assign	sllwer = (op1[31:0]) << (op2[4:0]);
assign	srlwer = (op1[31:0]) >> (op2[4:0]);
assign	srawer = $signed(op1[31:0]) >>> (op2[4:0]);

always @(*)
  begin
	if(rst)
		exe_data = 64'd0;
	else
		case(inst_opcode)
		8'b000_00100:	exe_data = adder;			//addi
		8'b110_00100:	exe_data = op1 | op2;			//ori
		8'b111_00100:	exe_data = op1 & op2;			//andi
		8'b001_00100:	exe_data = sller;	//slli
/*		8'b010_00100,8'b010_01100:			//slti,slt
					begin
						if((op1[`REG_DATA_LEN-1] == 1'b1) && (op2[`REG_DATA_LEN-1] == 1'b0))
							exe_data = 1'b1;
						else if((op1[`REG_DATA_LEN-1] == 1'b0) && (op2[`REG_DATA_LEN-1] == 1'b1))
							exe_data = 1'b0;
						else if((op1[`REG_DATA_LEN-1] == 1'b0) && (op2[`REG_DATA_LEN-1] == 1'b0))
							exe_data = (op1 < op2) ? 1'b1 : 1'b0;
						else
							exe_data = (op1 > op2) ? 1'b1 : 1'b0;
					end	*/
		8'b010_00100,8'b010_01100:	exe_data = (suber[63] == 1'b1) ? 1'b1 : 1'b0;	//slti,slt
		8'b011_00100,8'b011_01100:	exe_data = (op1 < op2) ? 1'b1 : 1'b0;	//stliu,sltu
//		8'b101_00100:	exe_data = ({`REG_DATA_LEN{op1[`REG_DATA_LEN-1]}} << (~op2[5:0])) | (op1 >> op2[5:0]);	//srai
		8'b101_00100:	exe_data = (funct7[5]) ? sraer : srler;	//srai_srli
		8'b100_00100:	exe_data = op1 ^ op2;				//xori
		8'b000_00000:	exe_data = adder;				//lb
		8'b100_00000:	exe_data = adder;				//lbu
		8'b001_00000:	exe_data = adder;				//lh
		8'b101_00000:	exe_data = adder;				//lhu
		8'b010_00000:	exe_data = adder;				//lw
		8'b110_00000:	exe_data = adder;				//lwu
		8'b000_11001:	exe_data = adder;				//jalr
		8'b011_00000:	exe_data = adder;				//ld
		8'b000_01100:	exe_data = (funct7[5]) ? suber : adder;				//add_sub
		8'b111_01100:	exe_data = op1 & op2;				//and
		8'b110_01100:	exe_data = op1 | op2;				//or
		8'b100_01100:	exe_data = op1 ^ op2;				//xor
//		8'b101_01100:	exe_data = (op1 >> op2[5:0]);		//srl
		8'b001_01100:	exe_data = sller;		//sll
		8'b000_00110:	exe_data = {{32{adder[31]}},adder[31:0]};	//addiw
		8'b001_00110:	exe_data = {{32{sllwer[31]}},sllwer[31:0]};		//slliw
		8'b101_00110:	exe_data = (funct7[5]) ? {{32{srawer[31]}},srawer[31:0]} : {{32{srlwer[31]}},srlwer[31:0]};			//srliw_sraiw
//csr
		8'b001_11100,8'b010_11100,8'b011_11100,8'b101_11100,8'b110_11100,8'b111_11100:	exe_data = csr_r_data;				

		8'b000_01110:	exe_data = (funct7[5]) ? ({{32{suber[31]}},suber[31:0]}) : {{32{adder[31]}},adder[31:0]};		//addw,subw
		8'b001_01110:	exe_data = {{32{sllwer[31]}},sllwer[31:0]};		//sllw
		8'b101_01110:	exe_data = (funct7[5]) ? {{32{srawer[31]}},srawer[31:0]} : {{32{srlwer[31]}},srlwer[31:0]};		//sraw_srlw
//		8'b010_01100:										//slt
//		8'b101_01100:	exe_data = ({`REG_DATA_LEN{op1[`REG_DATA_LEN-1]}} << (~op2[5:0])) | (op1 >> op2[5:0]);		//sra
		8'b101_01100:	exe_data = (funct7[5]) ? sraer : srler;			//srl_sra
		8'b000_01000,8'b001_01000,8'b010_01000,8'b011_01000:	exe_data = op1 + extend_imm;		//sb,sh,sw,sd
		8'b000_11000,8'b001_11000,8'b100_11000,8'b101_11000,8'b110_11000,8'b111_11000:	exe_data = pc + extend_imm;			//beq,bne,blt,bge,bltu,bgeu
		8'b000_01101,8'b001_01101,8'b010_01101,8'b011_01101,8'b100_01101,8'b101_01101,8'b110_01101,8'b111_01101:	
						exe_data = extend_imm;			//lui
		8'b000_00101,8'b001_00101,8'b010_00101,8'b011_00101,8'b100_00101,8'b101_00101,8'b110_00101,8'b111_00101:	
						exe_data = pc + extend_imm;		//auipc
		8'b000_11011,8'b001_11011,8'b010_11011,8'b011_11011,8'b100_11011,8'b101_11011,8'b110_11011,8'b111_11011:	
						exe_data = pc + extend_imm;				//jal
		default:	exe_data = {`REG_DATA_LEN{1'b0}};
	
		endcase
  end
  
endmodule